using System;
using System.Net.Sockets;
using System.Threading;

namespace Taxhui.Utils.Network.Tcp.Awaitable
{
    /// <summary>
    /// 中间人
    /// </summary>
    public sealed class Awaiter : IDisposable
    {
        private static readonly Action<Awaiter, SocketError> SENTINEL = delegate { };
        private Action<Awaiter, SocketError> _continuation;
        
        public SocketAsyncEventArgs Args { get; } = new SocketAsyncEventArgs();
        #region 构造函数
        internal Awaiter()
        {
            Args.Completed += OnSaeaCompleted;
        }
        #endregion
        #region 完成异步操作事件
        private void OnSaeaCompleted(object sender, SocketAsyncEventArgs args)
        {
            //当_continuation为空时表示实例并未订阅事件将其赋值为一个空委托，之后直接Raise事件
            var continuation = _continuation ?? Interlocked.CompareExchange(ref _continuation, SENTINEL, null);
            if (continuation != null)
            {
                continuation.Invoke(this, Args.SocketError);
            }
        }
        #endregion
        #region 注册完成事件委托
        internal void OnCompleted(Action<Awaiter, SocketError> continuation)
        {
            //Interlocked.CompareExchange(ref _continuation, continuation, null)
            //_continuation == SENTINEL 表示之前没有订阅过事件但已发生过事件，本次订阅后直接触发事件
            if (_continuation == SENTINEL
                || Interlocked.CompareExchange(ref _continuation, continuation, null) == SENTINEL)
            {
                continuation.Invoke(this, Args.SocketError);
            }
        }
        #endregion
        #region 重置事件
        internal void Reset()
        {
            _continuation = null;
        }
        #endregion
        #region 析构函数
        public void Dispose()
        {
            Args.Dispose();
            _continuation = null;
        }
        #endregion
    }
}
